package com.netscenery.yang.model;

import java.math.BigInteger;

import com.netscenery.util.ILinkData;




public class RangeEx implements ILinkData{
	protected BigInteger min;
	protected BigInteger  max;
	protected BigInteger lowBound = INT32_LOW_BOUND;
	protected BigInteger highBound = INT32_HIGH_BOUND;	
	protected static final BigInteger INT8_LOW_BOUND = new BigInteger("-128");
	protected static final BigInteger INT8_HIGH_BOUND = new BigInteger("127");
	protected static final BigInteger INT16_LOW_BOUND = new BigInteger("-32768");
	protected static final BigInteger INT16_HIGH_BOUND = new BigInteger("32767");
	protected static final BigInteger INT32_LOW_BOUND = new BigInteger("-2147483648");
	protected static final BigInteger INT32_HIGH_BOUND = new BigInteger("2147483647");	
	protected static final BigInteger INT64_LOW_BOUND = new BigInteger("-9223372036854775808");
	protected static final BigInteger INT64_HIGH_BOUND = new BigInteger("9223372036854775807");	
	protected static final BigInteger UINT8_LOW_BOUND = new BigInteger("0");
	protected static final BigInteger UINT8_HIGH_BOUND = new BigInteger("255");	
	protected static final BigInteger UINT16_LOW_BOUND = new BigInteger("0");
	protected static final BigInteger UINT16_HIGH_BOUND = new BigInteger("65535");	
	protected static final BigInteger UINT32_LOW_BOUND = new BigInteger("0");
	protected static final BigInteger UINT32_HIGH_BOUND = new BigInteger("4294967295");	
	protected static final BigInteger UINT64_LOW_BOUND = new BigInteger("0");
	protected static final BigInteger UINT64_HIGH_BOUND = new BigInteger("18446744073709551615");
	protected boolean isUseLowBound = true;
	protected boolean isUseHighBound = true;
	

	/**
	 * ��ʼ��һ��ָ����������͵�rangeEx
	 * @param type
	 */
	public RangeEx(BuiltinType type){
		switch(type){
		
		case INT8:{
			this.lowBound = INT8_LOW_BOUND;
			this.highBound = INT8_HIGH_BOUND;
			break;
		}
		case INT16:{
			this.lowBound = INT16_LOW_BOUND;
			this.highBound = INT16_HIGH_BOUND;
			break;
		}
		case INT32:{
			this.lowBound = INT32_LOW_BOUND;
			this.highBound = INT32_HIGH_BOUND;
			break;
		}
		case INT64:{
			this.lowBound = INT64_LOW_BOUND;
			this.highBound = INT64_HIGH_BOUND;
			break;
		}
		case UINT8:{
			this.lowBound = UINT8_LOW_BOUND;
			this.highBound = UINT8_HIGH_BOUND;
			break;
		}
		case UINT16:{
			this.lowBound = UINT16_LOW_BOUND;
			this.highBound = UINT16_HIGH_BOUND;
			break;
		}
		case UINT32:{
			this.lowBound = UINT32_LOW_BOUND;
			this.highBound = UINT32_HIGH_BOUND;
			break;
		}
		case UINT64:{
			this.lowBound = UINT64_LOW_BOUND;
			this.highBound = UINT64_HIGH_BOUND;
			break;
		}
		default:{
			return;
		}
		}
	}
	/**
	 * constructor  ���һ�����е�rangeEx����һ��rangex���µ�rangeEx��������Ϊ
	 * ԴrangeEx�������Сֵ����Ӧ����ĳ��������ͼ̳�����һ��������͵������ 
	 * @param type
	 */
	public RangeEx(RangeEx type){

		if (null == type){
			return;
		}
		
		if (true == type.isUseLowBound){
			this.lowBound = type.lowBound;
		}
		else {
			this.lowBound = type.min;
		}
		if (true == type.isUseHighBound){
			this.highBound = type.highBound;
		}
		else {
			this.highBound = type.max;
		}	
		
		return;

	}
	
	public RangeEx(BigInteger lowbound, BigInteger highbound){
		this.lowBound = lowbound;
		this.highBound = highbound;
	}
	
	public RangeEx(BigInteger lowbound, BigInteger highbound,String min, String max){
		this(lowbound,highbound);
		setMin(min);
		setMax(max);
	}
	
	public RangeEx(BigInteger lowbound, BigInteger highbound,String str){
		this(lowbound,highbound);
		setMin(str);
		setMax(str);
	}
	
	public RangeEx(String str){
		this(str,str);
	}
	
	public RangeEx(String min, String max){
		if (null == min){
			return;
		}
		
		if (null == max){
			return;
		}
		
		setMin(min);
		setMax(max);
	}
	/**
	 * constructor 	
	 * @param min
	 * @param max
	 */
	public RangeEx(BuiltinType type,String min, String max){
		
		this(type);
		if (null == min){
			return;
		}
		
		if (null == max){
			return;
		}
		
		setMin(min);
		setMax(max);
	}
	
	public RangeEx(RangeEx type,String min, String max){
		this(type);
		if (null == min){
			return;
		}
		
		if (null == max){
			return;
		}
		
		setMin(min);
		setMax(max);
	}

	/**
	 * @return the min
	 */
	public String getMinEx() {
		if (this.isUseLowBound){
			return "min";
		}
		return min.toString();
	}
	
	public String getMin(){
		if (this.isUseLowBound){
			return this.lowBound.toString();
		}
		return min.toString();
	}
	/**
	 * @param min the min to set
	 */
	public boolean setMin(String min) {
		if (null == min){
			return false;
		}
		min = min.trim();
		if ("min".equals(min)){
			this.isUseLowBound = true;
			return true;
		}
		
		BigInteger minInteger = new BigInteger(min);
		if (false == this.isUseHighBound){
			if (minInteger.compareTo(max) > 0){
				return false;
			}
		}
		else {
			if (minInteger.compareTo(highBound)>0){
				return false;
			}
		}
		
		if (minInteger.compareTo(lowBound) < 0){
			return false;
		}
		this.min = minInteger;		
		this.isUseLowBound = false;
		return true;
	}
	/**
	 * @return the max
	 */
	public String getMax() {
		if (this.isUseHighBound){
			return this.highBound.toString();
		}
		return max.toString();
	}
	/**
	 * @return the max
	 */
	public String getMaxEx() {
		if (this.isUseHighBound){
			return "max";
		}
		return max.toString();
	}
	
	/**
	 * @param max the max to set
	 */
	public boolean setMax(String max) {
		if (null == max){
			return false;
		}
		max = max.trim();
		if ("max".equals(max)){
			this.isUseHighBound = true;
			return true;			
		}
		
		BigInteger maxInteger = new BigInteger(max);
		
		if (false == this.isUseLowBound){
			if (maxInteger.compareTo(min) < 0){
				return false;
			}
		}
		else{
			if (maxInteger.compareTo(lowBound) < 0){
				return false;
			}
		}
		if (maxInteger.compareTo(highBound) > 0){
			return false;
		}
		this.max = maxInteger;
		this.isUseHighBound = false;
		return true;
	}
	/**
	 * @return the isUseLowBound
	 */
	public boolean isUseLowBound() {
		return isUseLowBound;
	}

	/**
	 * @return the isUseHighBound
	 */
	public boolean isUseHighBound() {
		return isUseHighBound;
	}
	
	public boolean isInRangeEx(BigInteger bi){
		if (null == bi){
			return false;
		}
		
		if (this.isUseHighBound == true){
			if (bi.compareTo(highBound) > 0){
				return false;
			}
		}
		else {
			if (bi.compareTo(max) > 0){
				return false;
			}
		}
		
		if (this.isUseLowBound == true){
			if (bi.compareTo(lowBound) < 0){
				return false;
			}
		}
		else {
			if (bi.compareTo(min) < 0){
				return false;
			}
		}
		
		return true;
	}
	
	public boolean isInRangeEx(String str){
		if (null == str){
			return false;
		}
		
		BigInteger bi = new BigInteger(str);
		
		return isInRangeEx(bi);
	}
	/**
	 * 
	 * @param rangeEx
	 * @return
	 */
	public boolean isInRangeEx(RangeEx rangeEx){
		if (null == rangeEx){
			return false;
		}
		
		if (!isInRangeEx(rangeEx.getMin())){
			return false;
		}
		
		if (!isInRangeEx(rangeEx.getMax())){
			return false;
		}
		
		return true;
	}
	
	public boolean hasInterSection(RangeEx range){
		if (null == range){
			return false;
		}
		
		if (range.isUseHighBound == true){
			if (range.isUseLowBound == true){
				return true;
			}
			
			if (isInRangeEx(range.min)){
				return true;
			}
			
			if (range.min.compareTo(this.isUseLowBound?this.lowBound:this.min) < 0){
				return true;
			}
		}
		else if (range.isUseLowBound == true){
			if (isInRangeEx(range.max)){
				return true;
			}
			
			if (range.max.compareTo(this.isUseHighBound?this.highBound:this.max) > 0){
				return true;
			}
		}
		else {
			if (isInRangeEx(range.max)){
				return true;
			}
			
			if (isInRangeEx(range.min)){
				return true;
			}
			
			if ((range.min.compareTo(this.min) < 0 ) 
					&& (range.max.compareTo(this.max) > 0)){
				return true;
			}
		}
		
		return false;
	}

	public String getExpression(){
		
		if (this.getMin().equals(this.getMax())){
			return this.getMin();
		}
		
		StringBuffer sb = new StringBuffer(this.getMinEx());
		sb.append("..");
		sb.append(this.getMaxEx());
		return sb.toString();
	}
	
	public boolean parseExpression(String expression){
		if (null == expression){
			return false;
		}
		
		if (!expression.contains("..")){
			this.setMin(expression);
			this.setMax(expression);
			return true;
		}
//		if (expression.equals("1..2147483647")){
//			int i = 0;
//			i++;
//		}
		String[] strs = expression.split("\\.\\.");
		if (2 != strs.length){
			return false;
		}
		
		setMin(strs[0]);
		setMax(strs[1]);
		return true;		
	}
	@Override
	/**
	 * self and dst must have no interSection
	 */
	public int compare(Object o) {
		// TODO Auto-generated method stub
		RangeEx  dst= (RangeEx) o;
		if (null == dst){
			return 1;
		}
		if (new BigInteger(this.getMin()).compareTo(new BigInteger(dst.getMax()))> 0){
			return 1;
		}
		else if (new BigInteger(this.getMax()).compareTo(new BigInteger(dst.getMin()))<0){
			return -1;
		}
		
		
		return 0;
	}
}
